require"cvscanner"
require"cvparser"

print"test cvscanner"

local function assert_s(result, type, value, line)
	assert(result.type == type, "("..(result.type or 'nil')..", "..type..")")
	assert(result.value == value, "("..(result.value or 'nil')..", "..(value or 'nil')..")")
	assert(result.line == line, "("..(result.line or 'nil')..", "..line..")")
end

local f = cvscanner.create(" local x ")
assert_s(f(), "local", nil, 1)
assert_s(f(), "id", "x", 1)
local r, e = f()
assert(r == nil)
assert(e == "EOF")

f = cvscanner.create("x, y, z = 1, nil, 'simple'; ")
assert_s(f(), "id", "x", 1)
assert_s(f(), ",", nil, 1)
assert_s(f(), "id", "y", 1)
assert_s(f(), ",", nil, 1)
assert_s(f(), "id", "z", 1)
assert_s(f(), "=", nil, 1)
assert_s(f(), "number", "1", 1)
assert_s(f(), ",", nil, 1)
assert_s(f(), "nil", nil, 1)
assert_s(f(), ",", nil, 1)
assert_s(f(), "string", "simple", 1)
assert_s(f(), ";", nil, 1)

f = cvscanner.create([['first string' "second string" "another \"string"]])
assert_s(f(), "string", "first string", 1)
assert_s(f(), "string", "second string", 1)
assert_s(f(), "string", "another \\\"string", 1)

f = cvscanner.create("f(2, 2.564, -5.4, .56, 12., ...)")
assert_s(f(), "id", "f", 1)
assert_s(f(), "(", nil, 1)
assert_s(f(), "number", "2", 1)
assert_s(f(), ",", nil, 1)
assert_s(f(), "number", "2.564", 1)
assert_s(f(), ",", nil, 1)
assert_s(f(), "-", nil, 1)
assert_s(f(), "number", "5.4", 1)
assert_s(f(), ",", nil, 1)
assert_s(f(), "number", ".56", 1)
assert_s(f(), ",", nil, 1)
assert_s(f(), "number", "12.", 1)
assert_s(f(), ",", nil, 1)
assert_s(f(), "...", nil, 1)
assert_s(f(), ")", nil, 1)

f = cvscanner.create("line = (line or 2) + 1")
assert_s(f(), "id", "line", 1)
assert_s(f(), "=", nil, 1)
assert_s(f(), "(", nil, 1)
assert_s(f(), "id", "line", 1)
assert_s(f(), "or", nil, 1)
assert_s(f(), "number", "2", 1)
assert_s(f(), ")", nil, 1)
assert_s(f(), "+", nil, 1)
assert_s(f(), "number", "1", 1)

f = cvscanner.create("a[#a + 1] = scan()")
assert_s(f(), "id", "a", 1)
assert_s(f(), "[", nil, 1)
assert_s(f(), "#", nil, 1)
assert_s(f(), "id", "a", 1)
assert_s(f(), "+", nil, 1)
assert_s(f(), "number", "1", 1)
assert_s(f(), "]", nil, 1)
assert_s(f(), "=", nil, 1)
assert_s(f(), "id", "scan", 1)
assert_s(f(), "(", nil, 1)
assert_s(f(), ")", nil, 1)

local source = [=[
	-- comment 1
	--[[
		long comment 1
	]]
	local t = {'banana', 'abacate'}
	-- comment 2
	for i, v in ipairs(t) do
		if #v == 10 then 
			return true
		elseif v >= 5 then
			return false
		else 
			return nil
		end
	end
	-- comment 3
	--[[
		long 
		comment 2
	]]
	-- comment 4
	t = nil
	-- comment 5
]=]

f = cvscanner.create(source)
assert_s(f(), "local", nil, 5)
assert_s(f(), "id", "t", 5)
assert_s(f(), "=", nil, 5)
assert_s(f(), "{", nil, 5)
assert_s(f(), "string", "banana", 5)
assert_s(f(), ",", nil, 5)
assert_s(f(), "string", "abacate", 5)
assert_s(f(), "}", nil, 5)

assert_s(f(), "for", nil, 7)
assert_s(f(), "id", "i", 7)
assert_s(f(), ",", nil, 7)
assert_s(f(), "id", "v", 7)
assert_s(f(), "in", nil, 7)
assert_s(f(), "id", "ipairs", 7)
assert_s(f(), "(", nil, 7)
assert_s(f(), "id", "t", 7)
assert_s(f(), ")", nil, 7)
assert_s(f(), "do", nil, 7)

assert_s(f(), "if", nil, 8)
assert_s(f(), "#", nil, 8)
assert_s(f(), "id", "v", 8)
assert_s(f(), "==", nil, 8)
assert_s(f(), "number", "10", 8)
assert_s(f(), "then", nil, 8)

assert_s(f(), "return", nil, 9)
assert_s(f(), "true", nil, 9)

assert_s(f(), "elseif", nil, 10)
assert_s(f(), "id", "v", 10)
assert_s(f(), ">=", nil, 10)
assert_s(f(), "number", "5", 10)
assert_s(f(), "then", nil, 10)

assert_s(f(), "return", nil, 11)
assert_s(f(), "false", nil, 11)

assert_s(f(), "else", nil, 12)

assert_s(f(), "return", nil, 13)
assert_s(f(), "nil", nil, 13)

assert_s(f(), "end", nil, 14)
assert_s(f(), "end", nil, 15)

assert_s(f(), "id", "t", 22)
assert_s(f(), "=", nil, 22)
assert_s(f(), "nil", nil, 22)

source = [[
	x = [====[
		long string 1
	]====]

	[==[
		long string 2
	]==]:len()
	
]]

f = cvscanner.create(source)
assert_s(f(), "id", "x", 1)
assert_s(f(), "=", nil, 1)
assert_s(f(), "string", "\n\t\tlong string 1\n\t", 3)
assert_s(f(), "string", "\n\t\tlong string 2\n\t", 7)
assert_s(f(), ":", nil, 7)
assert_s(f(), "id", "len", 7)
assert_s(f(), "(", nil, 7)
assert_s(f(), ")", nil, 7)

f = cvscanner.create("if x > 2^4 and not -y < z/2 and then break end")
assert_s(f(), "if", nil, 1)
assert_s(f(), "id", "x", 1)
assert_s(f(), ">", nil, 1)
assert_s(f(), "number", "2", 1)
assert_s(f(), "^", nil, 1)
assert_s(f(), "number", "4", 1)
assert_s(f(), "and", nil, 1)
assert_s(f(), "not", nil, 1)
assert_s(f(), "-", nil, 1)
assert_s(f(), "id", "y", 1)
assert_s(f(), "<", nil, 1)
assert_s(f(), "id", "z", 1)
assert_s(f(), "/", nil, 1)
assert_s(f(), "number", "2", 1)
assert_s(f(), "and", nil, 1)
assert_s(f(), "then", nil, 1)
assert_s(f(), "break", nil, 1)
assert_s(f(), "end", nil, 1)

f = cvscanner.create("while true do send(1) end")
assert_s(f(), "while", nil, 1)
assert_s(f(), "true", nil, 1)
assert_s(f(), "do", nil, 1)
assert_s(f(), "id", "send", 1)
assert_s(f(), "(", nil, 1)
assert_s(f(), "number", "1", 1)
assert_s(f(), ")", nil, 1)
assert_s(f(), "end", nil, 1)

f = cvscanner.create("function () repeat send(1)..' fim' until 2*x ~= 4%2 and x <= 14 end end")
assert_s(f(), "function", nil, 1)
assert_s(f(), "(", nil, 1)
assert_s(f(), ")", nil, 1)
assert_s(f(), "repeat", nil, 1)
assert_s(f(), "id", "send", 1)
assert_s(f(), "(", nil, 1)
assert_s(f(), "number", "1", 1)
assert_s(f(), ")", nil, 1)
assert_s(f(), "..", nil, 1)
assert_s(f(), "string", " fim", 1)
assert_s(f(), "until", nil, 1)
assert_s(f(), "number", "2", 1)
assert_s(f(), "*", nil, 1)
assert_s(f(), "id", "x", 1)
assert_s(f(), "~=", nil, 1)
assert_s(f(), "number", "4", 1)
assert_s(f(), "%", nil, 1)
assert_s(f(), "number", "2", 1)
assert_s(f(), "and", nil, 1)
assert_s(f(), "id", "x", 1)
assert_s(f(), "<=", nil, 1)
assert_s(f(), "number", "14", 1)
assert_s(f(), "end", nil, 1)
assert_s(f(), "end", nil, 1)

f = cvscanner.create("local $x")
assert_s(f(), "local", nil, 1)
r, e = f()
assert(r == nil)
assert(e ~= nil and type(e) == 'string')

print"cvscanner - ok\n"

print"test cvparser"

r = cvparser.parse"return"
assert(r)
assert(#r == 1)
assert(r[1].type == "return")
assert(#r[1] == 0)

r = cvparser.parse"return;"
assert(r)
assert(#r == 1)
assert(r[1].type == "return")
assert(#r[1] == 0)

r = cvparser.parse" return ; "
assert(r)
assert(#r == 1)
assert(r[1].type == "return")
assert(#r[1] == 0)

r = cvparser.parse"break"
assert(r)
assert(#r == 1)
assert(r[1].type == "break")
assert(#r[1] == 0)

r = cvparser.parse"break;"
assert(r)
assert(#r == 1)
assert(r[1].type == "break")
assert(#r[1] == 0)

r = cvparser.parse" break ; "
assert(r)
assert(#r == 1)
assert(r[1].type == "break")
assert(#r[1] == 0)

r = cvparser.parse"return 12.0, nil, false, true, 'simple string' ;"
assert(r)
assert(#r == 1)
local v = r[1]
assert(#v == 5)
assert(v[1].type == "number")
assert(v[1].value == "12.0")
assert(v[2].type == "nil")
assert(v[3].type == "false")
assert(v[4].type == "true")
assert(v[5].type == "string")
assert(v[5].value == "simple string")

r = cvparser.parse"do end"
assert(r)
assert(#r == 1)
assert(r[1].type == "block")
assert(#r[1] == 0)

r = cvparser.parse"do break end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "block")
assert(#b == 1)
assert(b[1].type == "break")

r = cvparser.parse"do break; end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "block")
assert(#b == 1)
assert(b[1].type == "break")

r = cvparser.parse"do return .898 end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "block")
assert(#b == 1)
b = b[1]
assert(b.type == "return")
assert(#b == 1)
assert(b[1].type == "number")
assert(b[1].value == ".898")

r = cvparser.parse"while true do return true end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "while")
assert(b.cond.type == "true")
local bl = b.block
assert(bl)
assert(bl[1].type == "return")
assert(bl[1][1].type == "true")

r = cvparser.parse"repeat break until true"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "repeat")
assert(#b.block == 1)
assert(b.block[1].type == "break")
assert(b.cond.type == "true")

r = cvparser.parse"if true then break end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "if")
assert(b.cond)
assert(b.block)
assert(b.cond.type == "true")
assert(b.block.type == "block")
assert(b.block[1].type == "break")
assert(b[1] == nil)
assert(b.elseblock == nil)

r = cvparser.parse"if true then break else break end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "if")
assert(b.cond)
assert(b.block)
assert(b.cond.type == "true")
assert(b.block.type == "block")
assert(b.block[1].type == "break")
assert(b[1] == nil)
assert(b.elseblock)
assert(b.elseblock.type == "block")
assert(b.elseblock[1].type == "break")

r = cvparser.parse"if true then break elseif false then break else break end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "if")
assert(b.cond)
assert(b.block)
assert(b.cond.type == "true")
assert(b.block.type == "block")
assert(b.block[1].type == "break")
assert(b[1])
assert(b[1].type == "elseif")
assert(b[1].cond)
assert(b[1].block)
assert(b[1].block.type == "block")
assert(b[1].block[1].type == "break")
assert(b.elseblock)
assert(b.elseblock.type == "block")
assert(b.elseblock[1].type == "break")

r = cvparser.parse"for i = 1, 10 do break end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "for")
assert(b.var.type == "id")
assert(b.var.value == "i")
assert(b.init.type == "number")
assert(b.init.value == "1")
assert(b.limit.value == "10")
assert(b.step.value == "1")
assert(b.block.type == "block")
assert(b.block[1].type == "break")

r = cvparser.parse"for i = 1, 10, 2 do break end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "for")
assert(b.var.type == "id")
assert(b.var.value == "i")
assert(b.init.type == "number")
assert(b.init.value == "1")
assert(b.limit.value == "10")
assert(b.step.value == "2")
assert(b.block.type == "block")
assert(b.block[1].type == "break")

r = cvparser.parse"for i, v in 10, 11 do break end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "for")
assert(b.names)
assert(#b.names == 2)
assert(b.names[1] == "i")
assert(b.names[2] == "v")
assert(b.exps)
assert(#b.exps == 2)
assert(b.exps[1].type == "number")
assert(b.exps[1].value == "10")
assert(b.exps[2].type == "number")
assert(b.exps[2].value == "11")
assert(b.block)
assert(b.block.type == "block")
assert(b.block[1].type == "break")

r = cvparser.parse"a = 1"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "att")
local var = b.vars[1]
assert(var.type == "var")
assert(var.name.type == "id")
assert(var.name.value == "a")
local exp = b.exps[1]
assert(exp.type == "number")
assert(exp.value == "1")

r = cvparser.parse"a.b = 1"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "att")
local var = b.vars[1]
assert(var.type == "var")
assert(var.prefix.type == "id")
assert(var.prefix.value == "a")
assert(var.index.type == "id")
assert(var.index.value == "b")
local exp = b.exps[1]
assert(exp.type == "number")
assert(exp.value == "1")

r = cvparser.parse"a[2] = 1"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "att")
local var = b.vars[1]
assert(var.prefix.type == "id")
assert(var.prefix.value == "a")
assert(var.index.type == "number")
assert(var.index.value == "2")
local exp = b.exps[1]
assert(exp.type == "number")
assert(exp.value == "1")

r = cvparser.parse"a[2].b = 1"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "att")
local var = b.vars[1]
assert(var.index.type == "id")
assert(var.index.value == "b")
var = var.prefix
assert(var.prefix.type == "id")
assert(var.prefix.value == "a")
assert(var.index.type == "number")
assert(var.index.value == "2")
local exp = b.exps[1]
assert(exp.type == "number")
assert(exp.value == "1")

r = cvparser.parse"a[2].b()"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "functioncall")
assert(b.args)
assert(#b.args == 0)
assert(b.prefix.type == "var")
assert(b.prefix.index.type == "id")
assert(b.prefix.index.value == "b")
assert(b.prefix.prefix.type == "var")
assert(b.prefix.prefix.prefix.type == "id")
assert(b.prefix.prefix.prefix.value == "a")
assert(b.prefix.prefix.index.type == "number")
assert(b.prefix.prefix.index.value == "2")

r = cvparser.parse"a[2]:b()"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "functioncall")
assert(b.args)
assert(#b.args == 0)
assert(b.name.type == "id")
assert(b.name.value == "b")
assert(b.prefix.type == "var")
assert(b.prefix.prefix.type == "id")
assert(b.prefix.prefix.value == "a")
assert(b.prefix.index.type == "number")
assert(b.prefix.index.value == "2")

r = cvparser.parse"a[2]:b''"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "functioncall")
assert(b.args)
assert(b.args.type == "string")
assert(b.name.type == "id")
assert(b.name.value == "b")
assert(b.prefix.type == "var")
assert(b.prefix.prefix.type == "id")
assert(b.prefix.prefix.value == "a")
assert(b.prefix.index.type == "number")
assert(b.prefix.index.value == "2")

r = cvparser.parse"a[2]:b{}"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "functioncall")
assert(b.args)
assert(b.args.type == "tableconstructor")
assert(b.name.type == "id")
assert(b.name.value == "b")
assert(b.prefix.type == "var")
assert(b.prefix.prefix.type == "id")
assert(b.prefix.prefix.value == "a")
assert(b.prefix.index.type == "number")
assert(b.prefix.index.value == "2")

r = cvparser.parse"a():b()"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "functioncall")
assert(b.args)
assert(#b.args == 0)
assert(b.name.type == "id")
assert(b.name.value == "b")
assert(b.prefix.type == "functioncall")
assert(b.prefix.prefix.type == "id")
assert(b.prefix.prefix.value == "a")

r = cvparser.parse"(nil).b = 1"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "att")
local var = b.vars[1]
assert(var.prefix.type == "group")
assert(var.prefix.exp.type == "nil")
assert(var.index.type == "id")
assert(var.index.value == "b")
local exp = b.exps[1]
assert(exp.type == "number")
assert(exp.value == "1")

r = cvparser.parse"(nil):b()"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "functioncall")
assert(b.prefix.type == "group")
assert(b.prefix.exp.type == "nil")
assert(b.name.type == "id")
assert(b.name.value == "b")
assert(b.args)

r = cvparser.parse"function foo() return true, false end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "functiondecl")
assert(#b.name == 1)
assert(b.name[1].value == "foo")
local func = b.func
assert(func.type == "function")
assert(#func.params == 0)
assert(func.block.type == "block")
assert(#func.block == 1)
assert(func.block[1].type == "return")
assert(func.block[1][1].type == "true")
assert(func.block[1][2].type == "false")

r = cvparser.parse"function foo(a) return 2, true, false end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "functiondecl")
assert(#b.name == 1)
assert(b.name[1].value == "foo")
local func = b.func
assert(func.type == "function")
assert(#func.params == 1)
assert(func.params[1] == "a")
assert(func.block.type == "block")
assert(#func.block == 1)
assert(func.block[1].type == "return")
assert(func.block[1][1].type == "number")
assert(func.block[1][1].value == "2")
assert(func.block[1][2].type == "true")
assert(func.block[1][3].type == "false")

r = cvparser.parse"local j, m = 10, true"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "localdecl")
assert(#b.names == 2)
assert(b.names[1] == "j")
assert(b.names[2] == "m")
assert(#b.exps == 2)
assert(b.exps[1].value == "10")
assert(b.exps[2].type == "true")

r = cvparser.parse"local j, m"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "localdecl")
assert(#b.names == 2)
assert(b.names[1] == "j")
assert(b.names[2] == "m")
assert(b.exps == nil)

r = cvparser.parse"local function foo() return 10, true end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "localfunc")
assert(b.name == "foo")
assert(b.func.type == "function")
assert(#b.func.params == 0)
assert(b.func.block.type == "block")
assert(#b.func.block == 1)
assert(b.func.block[1].type == "return")
assert(#b.func.block[1] == 2)

r = cvparser.parse"local function foo(a) return 10, true end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "localfunc")
assert(b.name == "foo")
assert(b.func.type == "function")
assert(#b.func.params == 1)
assert(b.func.params[1] == "a")
assert(b.func.block.type == "block")
assert(#b.func.block == 1)
assert(b.func.block[1].type == "return")
assert(#b.func.block[1] == 2)

r = cvparser.parse"local function foo(a, ...) return 10, true end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "localfunc")
assert(b.name == "foo")
assert(b.func.type == "function")
assert(#b.func.params == 2)
assert(b.func.params[1] == "a")
assert(b.func.params[2] == "...")
assert(b.func.block.type == "block")
assert(#b.func.block == 1)
assert(b.func.block[1].type == "return")
assert(#b.func.block[1] == 2)

r = cvparser.parse"local a = {}"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "localdecl")
assert(#b.names == 1)
assert(#b.exps == 1)
assert(b.exps[1].type == "tableconstructor")
assert(#b.exps[1] == 0)

r = cvparser.parse"local a = {x = 1, ['y'] = 2, 50}"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "localdecl")
assert(#b.names == 1)
assert(#b.exps == 1)
assert(b.exps[1].type == "tableconstructor")
assert(#b.exps[1] == 3)
b = b.exps[1]
assert(b[1].index.type == "string")
assert(b[1].index.value == "x")
assert(b[1].value.type == "number")
assert(b[1].value.value == "1")
assert(b[2].index.type == "string")
assert(b[2].index.value == "y")
assert(b[2].value.type == "number")
assert(b[2].value.value == "2")
assert(b[3].index == nil)
assert(b[3].value.type == "number")
assert(b[3].value.value == "50")

r = cvparser.parse"local a = ..."
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "localdecl")
assert(#b.names == 1)
assert(#b.exps == 1)
b = b.exps[1]
assert(b.type == "...")

r = cvparser.parse"local a = function() return nil end"
assert(r)
assert(#r == 1)
local b = r[1]
assert(b.type == "localdecl")
assert(#b.names == 1)
assert(#b.exps == 1)
b = b.exps[1]
assert(b.type == "function")
assert(#b.params == 0)
assert(b.block)

r = cvparser.parse"return 34 + 4"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "+")
assert(b[1].type == "number")
assert(b[1].value == "34")
assert(b[2].type == "number")
assert(b[2].value == "4")

r = cvparser.parse"return 20 - 1"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "-")
assert(b[1].type == "number")
assert(b[1].value == "20")
assert(b[2].type == "number")
assert(b[2].value == "1")

r = cvparser.parse"return 2 * 31"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "*")
assert(b[1].type == "number")
assert(b[1].value == "2")
assert(b[2].type == "number")
assert(b[2].value == "31")

r = cvparser.parse"return 22 / 3"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "/")
assert(b[1].type == "number")
assert(b[1].value == "22")
assert(b[2].type == "number")
assert(b[2].value == "3")

r = cvparser.parse"return 20 % 4"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "%")
assert(b[1].type == "number")
assert(b[1].value == "20")
assert(b[2].type == "number")
assert(b[2].value == "4")

r = cvparser.parse"return 2 + 20 * 4"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "+")
assert(b[1].type == "number")
assert(b[1].value == "2")
assert(b[2].type == "*")
assert(b[2][1].type == "number")
assert(b[2][1].value == "20")
assert(b[2][2].type == "number")
assert(b[2][2].value == "4")

r = cvparser.parse"return 4 * 20 + 2"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "+")
assert(b[1].type == "*")
assert(b[1][1].type == "number")
assert(b[1][1].value == "4")
assert(b[1][2].type == "number")
assert(b[1][2].value == "20")
assert(b[2].type == "number")
assert(b[2].value == "2")

r = cvparser.parse"return 4 * (20 + 2)"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "*")
assert(b[1].type == "number")
assert(b[1].value == "4")
assert(b[2].type == "group")
assert(b[2].exp.type == "+")
assert(b[2].exp[1].type == "number")
assert(b[2].exp[1].value == "20")
assert(b[2].exp[2].type == "number")
assert(b[2].exp[2].value == "2")

r = cvparser.parse"return a and b"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "and")
assert(b[1].type == "var")
assert(b[1].name.value == "a")
assert(b[2].type == "var")
assert(b[2].name.value == "b")

r = cvparser.parse"return a or b"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "or")
assert(b[1].type == "var")
assert(b[1].name.value == "a")
assert(b[2].type == "var")
assert(b[2].name.value == "b")

r = cvparser.parse"return a or b and c"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "or")
assert(b[1].type == "var")
assert(b[1].name.value == "a")
assert(b[2].type == "and")
assert(b[2][1].type == "var")
assert(b[2][1].name.value == "b")
assert(b[2][2].type == "var")
assert(b[2][2].name.value == "c")

r = cvparser.parse"return a and b or c"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "or")
assert(b[1].type == "and")
assert(b[1][1].type == "var")
assert(b[1][1].name.value == "a")
assert(b[1][2].type == "var")
assert(b[1][2].name.value == "b")
assert(b[2].type == "var")
assert(b[2].name.value == "c")

r = cvparser.parse"return a and (b or c)"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "and")
assert(b[1].type == "var")
assert(b[1].name.value == "a")
assert(b[2].type == "group")
assert(b[2].exp.type == "or")
assert(b[2].exp[1].type == "var")
assert(b[2].exp[1].name.value == "b")
assert(b[2].exp[2].type == "var")
assert(b[2].exp[2].name.value == "c")

r = cvparser.parse"return 2^3^4"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "^")
assert(b[1].type == "number")
assert(b[1].value == "2")
assert(b[2].type == "^")
assert(b[2][1].type == "number")
assert(b[2][1].value == "3")
assert(b[2][2].type == "number")
assert(b[2][2].value == "4")

r = cvparser.parse"return 2..3..4"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "..")
assert(b[1].type == "number")
assert(b[1].value == "2")
assert(b[2].type == "..")
assert(b[2][1].type == "number")
assert(b[2][1].value == "3")
assert(b[2][2].type == "number")
assert(b[2][2].value == "4")

r = cvparser.parse"return not not - #a"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "unary")
assert(b.op == "not")
assert(b[1].type == "unary")
assert(b[1].op == "not")
assert(b[1][1].type == "unary")
assert(b[1][1].op == "-")
assert(b[1][1][1].type == "unary")
assert(b[1][1][1].op == "#")
assert(b[1][1][1][1].type == "var")
assert(b[1][1][1][1].name.value == "a")

r = cvparser.parse"return a == b and b ~= c"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "and")
assert(b[1].type == "==")
assert(b[1][1].type == "var")
assert(b[1][1].name.value == "a")
assert(b[1][2].type == "var")
assert(b[1][2].name.value == "b")
assert(b[2].type == "~=")
assert(b[2][1].type == "var")
assert(b[2][1].name.value == "b")
assert(b[2][2].type == "var")
assert(b[2][2].name.value == "c")

r = cvparser.parse"return a > b and b < c"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "and")
assert(b[1].type == ">")
assert(b[1][1].type == "var")
assert(b[1][1].name.value == "a")
assert(b[1][2].type == "var")
assert(b[1][2].name.value == "b")
assert(b[2].type == "<")
assert(b[2][1].type == "var")
assert(b[2][1].name.value == "b")
assert(b[2][2].type == "var")
assert(b[2][2].name.value == "c")

r = cvparser.parse"return a >= b and b <= c"
assert(r)
assert(#r == 1)
local b = r[1]
assert(#b == 1)
assert(b.type == "return")
b = b[1]
assert(b.type == "and")
assert(b[1].type == ">=")
assert(b[1][1].type == "var")
assert(b[1][1].name.value == "a")
assert(b[1][2].type == "var")
assert(b[1][2].name.value == "b")
assert(b[2].type == "<=")
assert(b[2][1].type == "var")
assert(b[2][1].name.value == "b")
assert(b[2][2].type == "var")
assert(b[2][2].name.value == "c")

print"cvparser - ok"


